#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QTimer>
#include <QTime>
#include <QDebug>
/*
作者：阿正
项目名称：IMX6ULL QT 485问询
参考资料：来源于网络
制作日期：2020年7月19日
功能：实现485温湿度传感器的自动问询，并且用界面动态显示数据结果。
制作时间：周末两天
博客：http://wenzheng.club
*/
unsigned int msg_flag =0;
quint8 testbuf[100];

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    //设置背景颜色
    palette.setColor(QPalette::Background,QColor(90,135,115));
    this->setPalette(palette);
    timer = new QTimer(this);  //配置定时器
    //关联槽函数
    connect(timer,SIGNAL(timeout()),this,SLOT(auto_send()));   //定时时间到执行的任务
    setWindowTitle("IMX6Ull&485");
    serialport = new QSerialPort;
    find_port();                    //查找可用串口
}

Widget::~Widget()
{
    delete ui;
    delete timer;
}

//查找串口
void Widget::find_port()
{
    //查找可用的串口
    //ui->com->clear();
    foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
    {
        QSerialPort serial;
        serial.setPort(info);   //设置串口
        if(serial.open(QIODevice::ReadWrite))
        {
            ui->com->addItem(serial.portName());        //显示串口名称
            serial.close();
        }
    }
}
//打开串口
void Widget::on_open_btn_clicked()
{
    update();
    sleep(100);      //延时100ms
    //find_port();     //重新查找com
    //初始化串口
    serialport->setPortName(ui->com->currentText());        //设置串口名
    if(serialport->open(QIODevice::ReadWrite))              //打开串口成功
    {
        serialport->setBaudRate(ui->baud->currentText().toInt());       //设置波特率
        switch(ui->bit->currentIndex())                   //设置数据位数
        {
        case 8:serialport->setDataBits(QSerialPort::Data8);break;
        default: break;
        }
        switch(ui->check_bit->currentIndex())                   //设置奇偶校验
        {
        case 0: serialport->setParity(QSerialPort::NoParity);break;
        default: break;
        }
        switch(ui->stop_bit->currentIndex())                     //设置停止位
        {
        case 1: serialport->setStopBits(QSerialPort::OneStop);break;
        case 2: serialport->setStopBits(QSerialPort::TwoStop);break;
        default: break;
        }
        serialport->setFlowControl(QSerialPort::NoFlowControl);     //设置流控制
        //连接槽函数
        QObject::connect(serialport, &QSerialPort::readyRead, this, &Widget::Read_Date);

        // 设置控件可否使用
        ui->open_btn->setEnabled(false);
        ui->close_btn->setEnabled(true);
        ui->send_btn->setEnabled(true);
    }
    else    //打开失败提示
    {
        sleep(100);
        QMessageBox::information(this,tr("Erro"),tr("Open the failure"),QMessageBox::Ok);
    }
}

//窗口显示串口传来的数据
void Widget::Read_Date()
{
    QByteArray buf;
    quint8 outChar4 ;
    buf = serialport->readAll();
    // 下面是很重要的部分，可以将QT输出的QByteArry拼接为16进制buf
    QDataStream out4(&buf,QIODevice::ReadWrite);    //将字节数组读入
    while(!out4.atEnd())
    {
        outChar4 = 0;
        out4>>outChar4;   //每字节填充一次，直到结束
        testbuf[msg_flag]=outChar4;
        msg_flag++;
        //qDebug() << testbuf[wendu_flag];
    }
    msg_flag =0;
    //下面开始计算16进制数据
    qint16 tem= (testbuf[3]<<8)+testbuf[4];
    qint16 hum = (testbuf[5]<<8)+testbuf[6];
    double tem_double = tem/10.00;
    double hum_double = hum/10.00;
    //    qDebug() << tem;
    //    qDebug() << hum;
    //UI界面的显示
    ui->temperature_bar->setValue(tem_double);
    ui->humidity_bar->setValue(hum_double);
    ui->temperature_label->setText(QString::number(tem_double));
    ui->humidity_label->setText(QString::number(hum_double));
    //  qDebug() << buf;
    if(!buf.isEmpty())          //将数据显示到文本串口
    {
        QString str = ui->rev_msg->toPlainText();
        // byteArray 转 16进制   注意：这里是转换成了16进制的字符串，并不是可以直接使用的16进制buf
        QByteArray temp = buf.toHex();
        ui->rev_msg->clear();
        ui->rev_msg->append(temp);
    }
    buf.clear();    //清空缓存区
}
//延时函数
void Widget::sleep( int msec)
{
    QTime dieTime = QTime::currentTime().addMSecs(msec);
    while( QTime::currentTime() < dieTime )
        QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
}

void Widget::on_exit_btn_clicked()
{
    timer->stop();
    close();
}

void Widget::on_send_btn_clicked()
{
    // 03 03 00 00 00 02 C5 E9
    //勾选了自动模式
    if(ui->smart_check->isChecked())
    {
        timer->start(200);  //开启定时器 200ms触发一次
    }else
    {
        //手动模式
        unsigned char buf[8]={0x03, 0x03 ,0x00 ,0x00, 0x00 ,0x02 ,0xC5 ,0xE9};
        serialport->write(reinterpret_cast<const char *>(buf), 8);
        serialport->flush();
    }
}

void Widget::auto_send()
{
    unsigned char buf[8]={0x03, 0x03 ,0x00 ,0x00, 0x00 ,0x02 ,0xC5 ,0xE9};
    serialport->write(reinterpret_cast<const char *>(buf), 8);
    serialport->flush();  //可以快速发送出去
    //可以实现不勾选自动框的时候，就停止自动问询
    if(!(ui->smart_check->isChecked()))
    {
        timer->stop();
    }
}

void Widget::on_close_btn_clicked()
{
    timer->stop();
    serialport->clear();        //清空缓存区
    serialport->close();        //关闭串口
    //使某些串口不可使用
    ui->send_btn->setEnabled(false);
    ui->open_btn->setEnabled(true);
    ui->close_btn->setEnabled(false);
}


//CRC校验码计算
unsigned short CRC16(unsigned char *pBuf,unsigned short len)
{
    unsigned short uCRC=0xFFFF;
    int i,j;
    for(i=0;i<len;i++)
    {
        uCRC^=(*(pBuf+i));
        for(j=0;j<8;j++)
        {
            if((uCRC&0x0001)==0x0001)
            {
                uCRC=(uCRC>>1);
                uCRC^=0xA001;
            }
            else
                uCRC=(uCRC>>1);
        }
    }
    return uCRC;
}
